package com.example.forum.commons.aop;

import com.baomidou.mybatisplus.core.toolkit.Assert;
import com.example.forum.commons.annotations.NoRepeatSubmit;
import com.example.forum.commons.tools.Constants;
import com.example.forum.commons.tools.StringUtil;
import com.example.forum.commons.tools.WebContextUtil;
import com.example.forum.commons.tools.redis.RedisHelper;
import com.example.forum.commons.tools.redis.RedisLock;
import com.example.forum.vo.JsonResult;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;

/**
 * @author liucheng
 * @since 2020/01/15
 * 防止接口重复提交
 */
@Aspect
@Component
public class RepeatSubmitAspect {

    @Autowired
    private RedisLock redisLock;

    @Autowired
    public RedisHelper redisHelper;

    @Pointcut("@annotation(noRepeatSubmit)")
    public void pointCut(NoRepeatSubmit noRepeatSubmit) {
    }

    @Around("pointCut(noRepeatSubmit)")
    public Object around(ProceedingJoinPoint pjp, NoRepeatSubmit noRepeatSubmit) throws Throwable {
        HttpServletRequest request = WebContextUtil.getRequest();
        Assert.notNull(request, "request can not null");
        // 此处用token+接口地址作为key
        String token = request.getHeader(Constants.HEADER_STRING);
        String path = request.getServletPath();
        String key = token+path;
        var flag = redisHelper.readValue(key);
        if (StringUtil.isEmpty(flag)) {
            redisHelper.writeString(key, "1", 5);
            return pjp.proceed();
        } else {
            return new JsonResult(HttpStatus.BAD_REQUEST, "重复请求，请稍后再试", null);
        }
    }


    private String getKey(String token, String path) {
        return token + path;
    }

    /**
     * 此方法应对异步多线程产生的高并发请求（使用redis加锁处理）
     */
//    @Around("pointCut(noRepeatSubmit)")
//    public Object around(ProceedingJoinPoint pjp, NoRepeatSubmit noRepeatSubmit) throws Throwable {
//        int lockSeconds = noRepeatSubmit.lockTime();
//        HttpServletRequest request = WebContextUtil.getRequest();
//        Assert.notNull(request, "request can not null");
//
//        // 此处用token+接口地址作为key
//        String token = request.getHeader(Constants.HEADER_STRING);
//        String path = request.getServletPath();
//        String key = getKey(token, path);
//        String clientId = UUID.randomUUID().toString();
//
//        boolean isSuccess = redisLock.tryLock(key, clientId, lockSeconds);
//
//        if (isSuccess) {
//            // 获取锁成功
//            Object result;
//            try {
//                // 执行进程
//                result = pjp.proceed();
//            } finally {
//                // 解锁
//                redisLock.releaseLock(key, clientId);
//            }
//            return result;
//        } else {
//            // 获取锁失败，认为是重复提交的请求
//            return new JsonResult(HttpStatus.BAD_REQUEST, "重复请求，请稍后再试", null);
//        }
//    }


}
